 /*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.icee.myth.server.actor;

import com.icee.myth.common.charInfo.CharDetailInfo;
import com.icee.myth.common.messageQueue.DBMessageQueue;
import com.icee.myth.common.messageQueue.ServerMessageQueue;
import com.icee.myth.common.protobufmessage.ProtobufMessage;
import com.icee.myth.config.MapConfig;
import com.icee.myth.config.VipNumGold;
import com.icee.myth.log.GameLogger;
import com.icee.myth.log.message.FileDebugGameLogMessage;
import com.icee.myth.log.message.GameLogMessage.GameLogType;
import com.icee.myth.log.message.builder.GameLogMessageBuilder;
import com.icee.myth.protobuf.ExternalCommonProtocol.*;
import com.icee.myth.protobuf.InternalCommonProtocol.PlayerDetailProto;
import com.icee.myth.protobuf.builder.ClientToMapBuilder;
import com.icee.myth.server.GameServer;
import com.icee.myth.server.activity.cardDrawActivity.CardDrawActivityTemplates;
import com.icee.myth.server.activity.normalActivity.NormalActivity;
import com.icee.myth.server.activity.stageActivity.StageActivityTemplates;
import com.icee.myth.server.base.BaseTargets;
import com.icee.myth.server.base.barrack.Barrack;
import com.icee.myth.server.base.council.Council;
import com.icee.myth.server.base.mine.Mine;
import com.icee.myth.server.base.occupy.OccupyInfo;
import com.icee.myth.server.base.occupy.OccupyInfos;
import com.icee.myth.server.base.ordnance.Ordnance;
import com.icee.myth.server.base.training.Training;
import com.icee.myth.server.battle.*;
import com.icee.myth.server.bill.Bill;
import com.icee.myth.server.bill.Order;
import com.icee.myth.server.card.Card;
import com.icee.myth.server.card.CardFactories;
import com.icee.myth.server.card.CardStaticInfo;
import com.icee.myth.server.card.Cards;
import com.icee.myth.server.card.cardDraw.CardDrawItem;
import com.icee.myth.server.card.cardDraw.CardDrawStaticInfo;
import com.icee.myth.server.card.cardDraw.CardDrawsConfig;
import com.icee.myth.server.contsign.ContSign;
import com.icee.myth.server.fighter.Fighter;
import com.icee.myth.server.hegemony.HegemonyTarget;
import com.icee.myth.server.hegemony.HegemonyTargets;
import com.icee.myth.server.index.PlayerIdsOfLevels;
import com.icee.myth.server.index.PlayerIdsOfRanks;
import com.icee.myth.server.item.Items;
import com.icee.myth.server.levelup.HumanLevelsConfig;
import com.icee.myth.server.levelup.HumanRankConfig;
import com.icee.myth.server.levelup.HumanRanksConfig;
import com.icee.myth.server.mail.Mails;
import com.icee.myth.server.message.dbMessage.builder.MapDBMessageBuilder;
import com.icee.myth.server.message.serverMessage.builder.MapMessageBuilder;
import com.icee.myth.server.notification.NotifySystem;
import com.icee.myth.server.notification.message.BillNotificationMessage;
import com.icee.myth.server.player.MapPlayer;
import com.icee.myth.server.quest.Quests;
import com.icee.myth.server.reward.CertainRewardInfo;
import com.icee.myth.server.reward.RewardItemInfo;
import com.icee.myth.server.sandbox.SandBox;
import com.icee.myth.server.sandbox.TargetSandbox;
import com.icee.myth.server.sandbox.TargetSandboxCard;
import com.icee.myth.server.social.BriefPlayerInfo;
import com.icee.myth.server.social.Relation;
import com.icee.myth.server.stage.*;
import com.icee.myth.server.talent.TalentStaticInfo;
import com.icee.myth.server.talent.TalentsConfig;
import com.icee.myth.server.timer.FlushDataTimer;
import com.icee.myth.server.timer.MTimer;
import com.icee.myth.server.vip.Vip;
import com.icee.myth.server.vip.VipGift;
import com.icee.myth.utils.Consts;
import com.icee.myth.utils.RandomGenerator;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Random;

/**
 *
 * @author liuxianke
 */
public class Human {

    public final int id;    // 玩家id
    public String name;     // 玩家名字
    public int lv;          // 玩家等级
    public int exp;         // 玩家经验
    public int rankLv;      // 玩家军衔等级
    public int rankExp;     // 玩家军衔经验（功勋）
    public int gold1;       // 黄金（充值）
    public int gold2;       // 黄金（非充值）
    public long silver;     // 白银
    public int energy;      // 体力
    public int token;       // 军令

    public int guideStep;     // 新手引导步骤号

    public Items items;     // 物品
    public Cards cards;     // 卡片背包
    
    public SandBox sandbox;
    public int maxPower;    // 历史最大战斗力

    public final Stages stages; // 关卡信息
    public Stage stage;             // Human所在的关卡（注意：Human不能同时在场景和关卡中，挑战时不能进入关卡）

    public Vip vip;         // vip
    public VipGift vipGift; // vip赠礼

    public int ip;          // 玩家登陆ip
    public long enterTime;  // 最近一次登陆游戏时间
    public long leaveTime;  // 最后一次离开游戏时间
    public long totalOnlineTime;    // 累计游戏时间
    public long nextWorldTalkTime;      // 下次允许世界频道发言时间
    public long nextBattlePermitTime;   // 下一次战斗录像许可观看时间

    public Quests quests;   // 任务

    public MapPlayer mapPlayer;    // Human角色对应的网络实体
    public boolean inGame = false;  // 游戏中标志
    public boolean hasCharged = false;   // 是否充值过
    
    // 签到
    public ContSign contSign;
    // 好友关系
    public Relation relation;
    // 助战陌生人
    public final LinkedList<BriefPlayerInfo> strangers = new LinkedList<BriefPlayerInfo>();

    public int lastBuyEnergyDay;  //最近购买体力的日期
    public int buyEnergyCount;    //最近购买体力的日期那一天的购买次数

    public Mails mails;     // 补偿

    public NormalActivity normalActivity;   // 普通活动

    public HegemonyTargets hegemonyTargets; // 争霸对手

    public int lastRefreshHegemonyDay;  // 最近刷新争霸列表的日期
    public int refreshHegemonyCount;    // 最近刷新争霸列表的日期那一天的刷新次数
    public int lastHegemonyPayDay;      // 最后一次领争霸军饷的日期

    public BaseTargets baseTargets;     // 据点征服目标（只有在列表中的目标才能征服）（不需存数据库）
    public OccupyInfo selfOccupyInfo;   // 注意：当玩家正在反抗时才设置该值，即当该值不为null时表示正在反抗
    public Training training;           // 城墙
    public Mine mine;                   // 银矿
    public Barrack barrack;             // 兵营
    public Ordnance ordnance;           // 军械所
    public Council council;             // 军机处

    private FlushDataTimer flushTimer; // 数据库刷新计时器
    public HumanUpdateTimer updateTimer = null;   // 角色场景刷新定时器
    public final HumanProtocolBuilder humanProtocolBuilder = new HumanProtocolBuilder();

    public class HumanProtocolBuilder {

        public PlayerDetailProto buildPlayerDetail() {
            PlayerDetailProto.Builder builder = PlayerDetailProto.newBuilder();

            builder.setCards(cards.buildCardsProto()); // 卡片信息
            builder.setItems(items.buildItemsProto()); // 物品信息
            builder.setStages(stages.buildStagesProto()); // 关卡信息

            builder.setSandbox(sandbox.buildSandboxProto());
            builder.setBuyEnergyCount(buyEnergyCount);
            builder.setLastBuyEnergyDay(lastBuyEnergyDay);
            builder.setNormalActivity(normalActivity.buildDBNormalActivityProto());
            builder.setQuests(quests.buildQuestsProto());
            builder.setVipLastDayExp(vip.lastDayExp);
            builder.setViplastExpDay(vip.lastExpDay);
            builder.setVipGift(vipGift.receiveFlag);
            
            builder.setContSign(contSign.buildDBContSignProto());

            builder.setGuideStep(guideStep);

            if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                assert (hegemonyTargets != null);                
                builder.setRefreshHegemonyCount(refreshHegemonyCount);
                builder.setLastRefreshHegemonyDay(lastRefreshHegemonyDay);
                builder.setLastHegemonyPayDay(lastHegemonyPayDay);
                builder.setHegemonyTargets(hegemonyTargets.buildDBHegemonyTargetsProto());
            }

            if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                assert (training != null);                
                builder.setTraining(training.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openMineLevel) {
                assert (mine != null);               
                builder.setMine(mine.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
                assert (barrack != null);                
                builder.setBarrack(barrack.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
                assert (ordnance != null);                
                builder.setOrdnance(ordnance.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
                assert (council != null);                
                builder.setCouncil(council.buildSlotsProto());
            }
            
            return builder.build();
        }

        public EnterGameCharProto buildEnterGameCharProto() {
            EnterGameCharProto.Builder builder = EnterGameCharProto.newBuilder();

            builder.setCid(id);
            builder.setName(name);
            builder.setGold1(gold1);
            builder.setGold2(gold2);
            builder.setSilver(silver);
            builder.setEnergy(energy);
            builder.setToken(token);
            builder.setLv(lv);
            builder.setExp(exp);
            builder.setRankLv(rankLv);
            builder.setRankExp(rankExp);
            builder.setMaxPower(maxPower);
            
            builder.setCards(cards.buildCardsProto()); // 卡片信息
            builder.setItems(items.buildItemsProto()); // 物品信息
            builder.setStages(stages.buildStagesProto()); // 关卡信息

            if (stage != null) {
                builder.setStageState(stage.buildStageStateProto());
            }

            builder.setSandbox(sandbox.buildSandboxProto());
            
            builder.setVip(vip.buildVipProto());
            builder.setVipGift(vipGift.receiveFlag);

            builder.setQuests(quests.buildQuestsProto());

            builder.setContSign(contSign.buildContSignProto());

            builder.setGuideStep(guideStep);

            builder.setBuyEnergyCount(buyEnergyCount);
            builder.setLastBuyEnergyDay(lastBuyEnergyDay);

            builder.setCurrentTime(GameServer.INSTANCE.getCurrentTime());
            builder.setEndForbidTalkTime(mapPlayer.endForbidTalkTime);

            if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                assert (hegemonyTargets != null);
                builder.setRefreshHegemonyCount(refreshHegemonyCount);
                builder.setLastRefreshHegemonyDay(lastRefreshHegemonyDay);
                builder.setLastHegemonyPayDay(lastHegemonyPayDay);
                builder.setHegemonyTargets(hegemonyTargets.buildHegemonyTargetsProto());
            }

            if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                assert (training != null);
                builder.setTraining(training.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openMineLevel) {
                assert (mine != null);
                builder.setMine(mine.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
                assert (barrack != null);
                builder.setBarrack(barrack.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
                assert (ordnance != null);
                builder.setOrdnance(ordnance.buildSlotsProto());
            }

            if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
                assert (council != null);
                builder.setCouncil(council.buildSlotsProto());
            }

            return builder.build();
        }
    }

    public class HumanUpdateTimer implements MTimer {

        @Override
        public boolean update(int difftime) {
            if (this == updateTimer) {
                Human.this.update(difftime);
                return true;
            } else {
                return false;
            }
        }
    }

    // 注意：Human构造是在主线程中调用
    public Human(int id, CharDetailInfo charDetailInfo) {
        assert (id == charDetailInfo.mid);
        this.id = id;
        this.name = charDetailInfo.name;
        this.gold1 = charDetailInfo.gold1;
        this.gold2 = charDetailInfo.gold2;
        this.silver = charDetailInfo.silver;
        this.energy = charDetailInfo.energy;
        this.token = charDetailInfo.token;
        this.lv = charDetailInfo.level;
        this.exp = charDetailInfo.experience;
        this.rankLv = charDetailInfo.rankLevel;
        this.rankExp = charDetailInfo.rankExperience;

        this.totalOnlineTime = charDetailInfo.totalOnlineTime;
        this.leaveTime = charDetailInfo.leaveTime;

        PlayerDetailProto detail = charDetailInfo.detail;
        if (detail != null) {
            // 从detail中恢复数据
            buyEnergyCount = detail.getBuyEnergyCount();
            lastBuyEnergyDay = detail.getLastBuyEnergyDay();

            guideStep = detail.getGuideStep();

            // 卡片背包
            cards = new Cards(this, detail.getCards());
            // 材料背包
            items = new Items(this, detail.getItems());
            // 关卡信息
            stages = new Stages(this, detail.getStages());
            // 布阵信息
            sandbox = new SandBox(this, detail.getSandbox());
            // vip信息
            vip = new Vip(this, charDetailInfo.vipLevel, charDetailInfo.vipExperience, detail.getVipLastDayExp(), detail.getViplastExpDay());
            // vip赠礼
            vipGift = new VipGift(this, detail.getVipGift());

            // 签到
            contSign = new ContSign(this, detail.getContSign());
            // 补偿
            mails = new Mails(this, charDetailInfo.mailInfo);
            // 活动
            if (detail.hasNormalActivity()) {
                normalActivity = new NormalActivity(this, detail.getNormalActivity());
            } else {
                normalActivity = new NormalActivity(this, null);
            }
            // 任务
            if (detail.hasQuests()) {
                quests = new Quests(this, detail.getQuests());
            } else {
                quests = new Quests(this, null);
            }

            // 争霸
            if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                refreshHegemonyCount = detail.getRefreshHegemonyCount();
                lastRefreshHegemonyDay = detail.getLastRefreshHegemonyDay();
                lastHegemonyPayDay = detail.getLastHegemonyPayDay();
                if (detail.hasHegemonyTargets()) {
                    hegemonyTargets = new HegemonyTargets(this, detail.getHegemonyTargets());
                } else {
                    hegemonyTargets = new HegemonyTargets(this, null);
                }
            }

            // 城墙
            if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                if (detail.hasTraining()) {
                    training = new Training(this, detail.getTraining());
                } else {
                    training = new Training(this, null);
                }
            }

            // 银矿
            if (lv >=MapConfig.INSTANCE.openMineLevel) {
                if (detail.hasMine()) {
                    mine = new Mine(this, detail.getMine());
                } else {
                    mine = new Mine(this, null);
                }
            }

            // 兵营
            if (lv >=MapConfig.INSTANCE.openBarrackLevel) {
                if (detail.hasBarrack()) {
                    barrack = new Barrack(this, detail.getBarrack());
                } else {
                    barrack = new Barrack(this, null);
                }
            }

            // 军械所
            if (lv >=MapConfig.INSTANCE.openOrdnanceLevel) {
                if (detail.hasOrdnance()) {
                    ordnance = new Ordnance(this, detail.getOrdnance());
                } else {
                    ordnance = new Ordnance(this, null);
                }
            }

            // 军机处
            if (lv >=MapConfig.INSTANCE.openCouncilLevel) {
                if (detail.hasCouncil()) {
                    council = new Council(this, detail.getCouncil());
                } else {
                    council = new Council(this, null);
                }
            }

        } else {
            energy = HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy;

            guideStep = 1;

            // 卡片背包
            cards = new Cards(this, null);
            Card card = cards.addCard(charDetailInfo.leaderCardId, charDetailInfo.leaderCardLevel, 0, false);
            // 材料背包
            items = new Items(this, null);
            // 关卡信息
            stages = new Stages(this, null);
            // 布阵信息
            sandbox = new SandBox(this, null);
            sandbox.slots[0] = card;
            sandbox.leader = 0;
            sandbox.helper = 1;
            // vip信息
            vip = new Vip(this, charDetailInfo.vipLevel, charDetailInfo.vipExperience, 0, 0);
            // vip赠礼
            vipGift = new VipGift(this, 0);
            // 签到
            contSign = new ContSign(this, null);
            // 补偿
            mails = new Mails(this, null);
            // 普通活动
            normalActivity = new NormalActivity(this, null);
            // 任务
            quests = new Quests(this, null);

            // 争霸
            if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
                lastHegemonyPayDay = (int) ((GameServer.INSTANCE.getCurrentTime()+Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
                hegemonyTargets = new HegemonyTargets(this, null);
            }

            // 城墙
            if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
                training = new Training(this, null);
            }

            // 银矿
            if (lv >=MapConfig.INSTANCE.openMineLevel) {
                mine = new Mine(this, null);
            }

            // 兵营
            if (lv >=MapConfig.INSTANCE.openBarrackLevel) {
                barrack = new Barrack(this, null);
            }

            // 军械所
            if (lv >=MapConfig.INSTANCE.openOrdnanceLevel) {
                ordnance = new Ordnance(this, null);
            }

            // 军机处
            if (lv >=MapConfig.INSTANCE.openCouncilLevel) {
                council = new Council(this, null);
            }
        }

        maxPower = charDetailInfo.maxPower;
        if (maxPower == 0) {
            maxPower = sandbox.getCurrentPower();
        }
    }
    
    public void setRelation(Relation relation) {
        if (this.relation == null) {
            relation.human = this;
            this.relation = relation;

            //send relation msg to client
            sendMessage(ClientToMapBuilder.buildRelationInfo(relation.buildRelationProto()));

            // 广播通知在线的follower该玩家上线
            if (!relation.friends.isEmpty()) {
                ProtobufMessage protobufMessage = ClientToMapBuilder.buildFriendEntered(id);
                for (Integer friendId : relation.friends.keySet()) {
                    MapPlayer friendPlayer = GameServer.INSTANCE.players.get(friendId);
                    if ((friendPlayer != null) && (friendPlayer.human != null) && (friendPlayer.human.inGame)) {
                        friendPlayer.human.sendMessage(protobufMessage);
                    }
                }
            }

            // 产生助战陌生人
            generateStrangers(true);
        } else {
            // 若玩家快速登录下线再登录，能使Relation下消息队列中出现两个“get info”消息，此时会到该分支中，但概率很低
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] multi-set relation error."));
        }
    }

    private void generateStrangers(boolean needSend) {
        strangers.clear();
        GameServer.INSTANCE.briefPlayerInfos.getStrangers(lv, id, relation.friends, strangers);

        if (needSend) {
            // 通知客户端助战陌生人信息
            sendMessage(ClientToMapBuilder.buildStrangers(strangers, id));
        }
    }

    /**
     * 与离线上线时间差相关的刷新
     */
    public void timeRefresh() {
        if (leaveTime != 0) {
            if (enterTime > leaveTime) {    // 系统时间可能被修改
                // 计算体力恢复
                int maxEnergy = HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy;
                if (energy < maxEnergy) {
                    // 计算经过几次加体力周期
                    long num = enterTime / MapConfig.INSTANCE.energyRecoverPeriod - leaveTime / MapConfig.INSTANCE.energyRecoverPeriod;

                    energy = (int) ((energy + num < maxEnergy) ? energy + num : maxEnergy);
                }

                // 计算军令恢复
                if (token < MapConfig.INSTANCE.maxTokenNum) {
                    // 计算经过几次加体力周期
                    long num = enterTime / MapConfig.INSTANCE.tokenRecoverPeriod - leaveTime / MapConfig.INSTANCE.tokenRecoverPeriod;

                    token = (int) ((token + num < MapConfig.INSTANCE.maxTokenNum) ? token + num : MapConfig.INSTANCE.maxTokenNum);
                }
            }
        }
    }

    public long getSilver() {
        return silver;
    }

    public int getGold() {
        return gold1 + gold2;
    }

    public int getGold1() {
        return gold1;
    }

    public int getGold2() {
        return gold2;
    }

    public float getAtkUp() {
        return (ordnance != null)?ordnance.atkIncrease:0 + HumanRanksConfig.INSTANCE.rankConfigs[rankLv-1].atkUp;
    }

    public float getHpUp() {
        return (barrack != null)?barrack.hpIncrease:0 + HumanRanksConfig.INSTANCE.rankConfigs[rankLv-1].hpUp;
    }

    public int getHitAndDodUp() {
        return (training != null)?training.hitAndDodIncrease:0;
    }

    public int getCriAndTenUp() {
        return (council != null)?council.criAndTenIncrease:0;
    }

    public void checkMaxPowerChange() {
        // 判断是否需要更新历史最高战斗力
        int currentPower = sandbox.getCurrentPower();

        if (currentPower > maxPower) {
            maxPower = currentPower;
        }
    }

    /**
     * 新手引导
     * @param curGuildStep
     */
    public void nextGuide(int curGuildStep) {
    	
        if (guideStep > 0) {
            if (guideStep == curGuildStep) {
                switch (guideStep) {
                    case 16: {
                        // 获得第一关奖励
                        increaseExperience(121, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 16, true);
                        increaseSilver(878, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 16, true);
                        
                        // 让第一关为通过状态（注意：附带会使第一个任务成为完成状态）
                        stages.finishState(0, false, true);

                        break;
                    }
                    case 19: {
                        // 完成第一个任务
                        quests.submit(0);

                        break;
                    }
                    case 23: {
                        // 更改阵型
                        SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                        VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                        VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                        builder3.setId(0);
                        builder3.setValue(1);
                        builder2.addValues(builder3);

                        VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                        builder4.setId(1);
                        builder4.setValue(2);
                        builder2.addValues(builder4);

                        builder1.setSlots(builder2);

                        builder1.setLeader(0);
                        builder1.setHelper(2);

                        sandbox.change(builder1.build());

                        break;
                    }
                    case 28: {
                        // 更改阵型
                        SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                        VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                        VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                        builder3.setId(0);
                        builder3.setValue(1);
                        builder2.addValues(builder3);

                        VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                        builder4.setId(4);
                        builder4.setValue(2);
                        builder2.addValues(builder4);

                        builder1.setSlots(builder2);

                        builder1.setLeader(0);
                        builder1.setHelper(2);

                        sandbox.change(builder1.build());

                        break;
                    }
                    case 32: {
                        // 获得第二关奖励
                        increaseExperience(123, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 32, true);
                        increaseSilver(514, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 32, true);
                        decreaseEnergy(10, true);
                        
                        // 让第二关为通过状态（会使第二个任务成为完成状态）
                        stages.finishState(1, false, true);

                        break;
                    }
                    case 35: {
                        // 完成第二个任务S
                        quests.submit(1);

                        break;
                    }
                    case 39: {
                        // 更改阵型
                        SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                        VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                        VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                        builder3.setId(0);
                        builder3.setValue(1);
                        builder2.addValues(builder3);

                        VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                        builder4.setId(1);
                        builder4.setValue(3);
                        builder2.addValues(builder4);

                        VariableValueProto.Builder builder5 = VariableValueProto.newBuilder();
                        builder5.setId(4);
                        builder5.setValue(2);
                        builder2.addValues(builder5);

                        builder1.setSlots(builder2);

                        builder1.setLeader(0);
                        builder1.setHelper(2);

                        sandbox.change(builder1.build());

                        break;
                    }
                    case 44: {
                        // 更改阵型
                        SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                        VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                        VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                        builder3.setId(1);
                        builder3.setValue(3);
                        builder2.addValues(builder3);

                        VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                        builder4.setId(3);
                        builder4.setValue(1);
                        builder2.addValues(builder4);

                        VariableValueProto.Builder builder5 = VariableValueProto.newBuilder();
                        builder5.setId(4);
                        builder5.setValue(2);
                        builder2.addValues(builder5);

                        builder1.setSlots(builder2);

                        builder1.setLeader(3);
                        builder1.setHelper(2);

                        sandbox.change(builder1.build());
                        break;
                    }
                    case 50: {
                        // 更改阵型
                        SandboxProto.Builder builder1 = SandboxProto.newBuilder();

                        VariableValuesProto.Builder builder2 = VariableValuesProto.newBuilder();

                        VariableValueProto.Builder builder3 = VariableValueProto.newBuilder();
                        builder3.setId(1);
                        builder3.setValue(3);
                        builder2.addValues(builder3);

                        VariableValueProto.Builder builder4 = VariableValueProto.newBuilder();
                        builder4.setId(3);
                        builder4.setValue(1);
                        builder2.addValues(builder4);

                        VariableValueProto.Builder builder5 = VariableValueProto.newBuilder();
                        builder5.setId(5);
                        builder5.setValue(2);
                        builder2.addValues(builder5);

                        builder1.setSlots(builder2);

                        builder1.setLeader(3);
                        builder1.setHelper(2);

                        sandbox.change(builder1.build());

                        break;
                    }
                    case 51: {
                        // 获得第三关奖励
                        increaseExperience(126, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 51, true);
                        increaseSilver(536, Consts.SOUL_CHANGE_LOG_TYPE_GUIDE, 51, true);

                        // 让第三关为通过状态（会使第三个任务成为完成状态）
                        stages.finishState(2, false, true);

                        break;
                    }
                    case 54: {
                        // 完成第三个任务
                        quests.submit(2);

                        break;
                    }
                    case 60: {
                        // 升级卡片（1号实例卡）
                        LinkedList<Integer> foodCardInstIds = new LinkedList<Integer>();
                        foodCardInstIds.add(4);
                        cards.strengthen(1, foodCardInstIds, true);

                        break;
                    }
                    /*
                    case 65: {
                        // 转生卡片（1号实例卡）
                        cards.transform(1, null, true);

                        break;
                    }
                     * */
                    case 63: {
                        // 抽卡片（注意：首抽必出紫卡）
                        cards.draw(6, Consts.CARD_DRAW_TYPE_GOLD_ONE_DRAW, true);

                        break;
                    }
                }
                
                guideStep++;
                if (guideStep > Consts.MAX_GUIDE_STEP) {
                    // 引导结束
                    guideStep = 0;
                }
              //TODO 跳过教程
            	guideStep = 0;
                sendMessage(ClientToMapBuilder.buildGuideStepChange(guideStep));
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't move to next guide because wrong param guide step[" + curGuildStep +"] not equal to current guide step[" + guideStep + "]"));
            }
        } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't move to next guide because not in guide"));
        }
    }

    public void talk(int channelType, String msg, int recvPlayerId) {
        if (mapPlayer.endForbidTalkTime <= 0 || GameServer.INSTANCE.getCurrentTime() >= mapPlayer.endForbidTalkTime) {
            S2CTalkProto.Builder talkProtoResp = S2CTalkProto.newBuilder();
            talkProtoResp.setChannelType(channelType);
            talkProtoResp.setMsg(msg);
            talkProtoResp.setSendPlayerId(id);
            talkProtoResp.setSendPlayerName(name);
            if (channelType == Consts.WORLDCHANNEL) {
                if ((lv >= Consts.ALLOW_TALK_LEVEL) && (GameServer.INSTANCE.getCurrentTime() >= nextWorldTalkTime)) {
                    GameServer.INSTANCE.broadcast(ClientToMapBuilder.buildTalk(talkProtoResp.build().toByteArray()));
                    nextWorldTalkTime = GameServer.INSTANCE.getCurrentTime() + Consts.MILSECOND_1SECOND;

                    if (MapConfig.INSTANCE.useCYLog == true) {
                        List<String> cyLogList = new ArrayList<String>();
                        cyLogList.add("behaviorMC");
                        cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                        cyLogList.add("KDTY");
                        cyLogList.add(String.valueOf(id));
                        cyLogList.add(name);
                        cyLogList.add("");
                        cyLogList.add("BroadcastDBBehavior");
                        cyLogList.add(msg);
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                    }

                    GameLogger.getlogger().log(GameLogMessageBuilder.buildBroadcastDBBehaviorGameLogMessage(id, msg));
                }
            } else if (channelType == Consts.PRIVATECHANNEL) {
                // 查看对话目标是否在黑名单中
                MapPlayer recvPlayer = GameServer.INSTANCE.players.get(recvPlayerId);
                if (recvPlayer != null && recvPlayer.human != null) {
                    talkProtoResp.setRecvPlayerId(recvPlayerId);
                    talkProtoResp.setRecvPlayerName(recvPlayer.human.name);
                    List<Integer> charIds = new ArrayList<Integer>(2);
                    charIds.add(id);
                    charIds.add(recvPlayerId);
                    GameServer.INSTANCE.broadcast(charIds, ClientToMapBuilder.buildTalk(talkProtoResp.build().toByteArray()), true);

                    if (MapConfig.INSTANCE.useCYLog == true) {
                        List<String> cyLogList = new ArrayList<String>();
                        cyLogList.add("behaviorMC");
                        cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                        cyLogList.add("KDTY");
                        cyLogList.add(String.valueOf(id));
                        cyLogList.add(name);
                        cyLogList.add("");
                        cyLogList.add("PrivateTalkDBBehavior");
                        cyLogList.add(recvPlayerId + " " + msg);
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                    }
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildPrivateTalkDBBehaviorGameLogMessage(id, recvPlayerId, msg));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't talk in channel[" + channelType + "]"));
            }
        }
    }
   
    public void increaseExperience(int num, int type, int subType, boolean needSend) {
        if (num > 0) {
            int maxLevel = HumanLevelsConfig.INSTANCE.maxLevel;
            if (lv < maxLevel) {
                int upLevel = 0;
                exp += num;

                if (MapConfig.INSTANCE.useCYLog == true) {
                    List<String> cyLogList = new ArrayList<String>();
                    cyLogList.add("behaviorMC");
                    cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                    cyLogList.add("KDTY");
                    cyLogList.add(String.valueOf(id));
                    cyLogList.add(name);
                    cyLogList.add("");
                    cyLogList.add("GetExperienceDBBehavior");
                    cyLogList.add(type + " " + subType + " " + num);
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                }
                GameLogger.getlogger().log(GameLogMessageBuilder.buildGetExperienceDBBehaviorGameLogMessage(id, type, subType, num));

                int levelupExperience = GameServer.INSTANCE.getHumanLevelupExperience(lv);
                while ((levelupExperience != -1) && (exp >= levelupExperience) && (lv + upLevel < maxLevel)) {
                    upLevel++;
                    exp -= levelupExperience;
                    levelupExperience = GameServer.INSTANCE.getHumanLevelupExperience(lv + upLevel);
                }

                if (lv + upLevel >= maxLevel) {
                    exp = 0;
                }

                if (upLevel > 0) {
                    levelup(upLevel, needSend);
                }
                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildExperienceChange(exp));
                }
            }
        }
    }

    public void increaseRankExperience(int num, int type, int subType, boolean needSend) {
        if (num > 0) {
            int maxLevel = HumanRanksConfig.INSTANCE.maxRank;
            if (rankLv < maxLevel) {
                int upLevel = 0;
                rankExp += num;

                if (MapConfig.INSTANCE.useCYLog == true) {
                    List<String> cyLogList = new ArrayList<String>();
                    cyLogList.add("behaviorMC");
                    cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                    cyLogList.add("KDTY");
                    cyLogList.add(String.valueOf(id));
                    cyLogList.add(name);
                    cyLogList.add("");
                    cyLogList.add("GetRankExperienceDBBehavior");
                    cyLogList.add(type + " " + subType + " " + num);
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                }

                GameLogger.getlogger().log(GameLogMessageBuilder.buildGetRankExperienceDBBehaviorGameLogMessage(id, type, subType, num));

                int rankLevelupExperience = GameServer.INSTANCE.getHumanRankLevelupExperience(rankLv);
                while ((rankLevelupExperience != -1) && (rankExp >= rankLevelupExperience) && (rankLv + upLevel < maxLevel)) {
                    upLevel++;
                    rankExp -= rankLevelupExperience;
                    rankLevelupExperience = GameServer.INSTANCE.getHumanRankLevelupExperience(rankLv + upLevel);
                }

                if (rankLv + upLevel >= maxLevel) {
                    rankExp = 0;
                }

                if (upLevel > 0) {
                    rankLevelup(upLevel, needSend);
                }
                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildRankExperienceChange(rankExp));
                }
            }
        }
    }

    public void increaseSilver(int num, int type, int subtype, boolean needSend) {
        if (num > 0) {
            if ((Long.MAX_VALUE - silver) > num) {
                silver += num;
            } else {
                silver = Long.MAX_VALUE;
            }
            if (needSend) {
                sendMessage(ClientToMapBuilder.buildSilverChange(silver));
            }

            GameLogger.getlogger().log(GameLogMessageBuilder.buildDBSilverGameLogMessage(id, type, subtype, num, silver));
        }
    }

    public void decreaseSilver(int num, int type, int subtype, boolean needSend) {
        if (num > 0) {
            silver -= num;
            if (needSend) {
                sendMessage(ClientToMapBuilder.buildSilverChange(silver));
            }

            GameLogger.getlogger().log(GameLogMessageBuilder.buildDBSilverGameLogMessage(id, type, subtype, -num, silver));
        }
    }

    public void increaseGold(int num1, int num2, int type, int subtype, boolean needSend) {
        if ((num1 > 0) || (num2 > 0)) {
            if (num1 > 0) {
                if ((Integer.MAX_VALUE - gold1) > num1) {
                    gold1 += num1;
                } else {
                    gold1 = Integer.MAX_VALUE;
                }
                
                vip.increaseVipExp(num1, needSend);

                // 修改充值活动状态
                normalActivity.chargeGold(num1);

                if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_INCREASE_YELLOWSOUL1) {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CHARGE , num1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "GM", 0));
                } else {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CHARGE , num1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "CHARGE", 0));
                }

                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildGold1Change(gold1));
                }
            }

            if (num2 > 0) {
                if ((Integer.MAX_VALUE - gold2) > num2) {
                    gold2 += num2;
                } else {
                    gold2 = Integer.MAX_VALUE;
                }

                if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_INCREASE_YELLOWSOUL2) {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CHARGE , num2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "GM", 0));
                } else {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_TASK_CHARGE , num2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "" + type + ":" + subtype, 0));
                }

                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildGold2Change(gold2));
                }
            }

            if (MapConfig.INSTANCE.useCYLog == true && num1 > 0) {
                List<String> cyLogList = new ArrayList<String>();
                cyLogList.add("rechargeMC");
                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                cyLogList.add("KDTY");
                cyLogList.add(String.valueOf(id));
                cyLogList.add(name);
                cyLogList.add(String.valueOf(type));                
                cyLogList.add(String.valueOf(num1));
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_RECHARGE));
            }

            if (MapConfig.INSTANCE.useCYLog == true) {
                List<String> cyLogList = new ArrayList<String>();
                cyLogList.add("diamondMC");
                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                cyLogList.add("KDTY");
                cyLogList.add(String.valueOf(id));
                cyLogList.add(name);
                cyLogList.add("");
                cyLogList.add(String.valueOf(lv));
                if (num1 > 0) {
                    cyLogList.add("1");
                    cyLogList.add(String.valueOf(num1));
                }
                else {
                    cyLogList.add("3");
                    cyLogList.add(String.valueOf(num2));
                }
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("0");
                cyLogList.add("");
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_DIAMOND));
            }

            GameLogger.getlogger().log(GameLogMessageBuilder.buildDBGoldGameLogMessage(id, type, subtype, num1, num2, gold1, gold2, lv));
        }
    }

    public void increaseGold1(String passport, Order order, int status) {
        Order order1 = GameServer.INSTANCE.billings.get(passport);        
        if (order1 == order) {
            if (status == 0 || status == 20100) {
                //int num = (order1.currencyId == 1) ? 10 * order1.amount : order1.amount;
                int num = order.price * order.amount;
                increaseGold(num, 0, Consts.SOUL_CHANGE_LOG_TYPE_BILL, Consts.SOUL_CHANGE_LOG_SUBTYPE_NONE, true);
                NotifySystem.INSTANCE.sendNote(id, new BillNotificationMessage(num), true);
            }
            GameServer.INSTANCE.billings.remove(passport);
            DBMessageQueue.queue().offer(MapDBMessageBuilder.buildSaveBillDBMessage(id, passport, order1, status, Consts.BILL_STEP_FINISH));
            Bill bill = new Bill(id, passport);
            GameServer.INSTANCE.executeBill(bill);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] passport " + passport + "receive bill result but this order isn't exist"));
        }
    }

    public void decreaseGold1(int num, int type, int subtype, boolean needSend) {
        if (num > 0) {
            int totoalDecreaseGold1 = 0;
            if (gold1 > num) {
                totoalDecreaseGold1 = num;
                gold1 -= num;
            } else {
                totoalDecreaseGold1 = gold1;
                gold1 = 0;
            }

            DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER , totoalDecreaseGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "GM", 0));

            if (needSend) {
                sendMessage(ClientToMapBuilder.buildGold1Change(gold1));
            }
            GameLogger.getlogger().log(GameLogMessageBuilder.buildDBGoldGameLogMessage(id, type, subtype, -num, 0, gold1, gold2, lv));
        }
    }
    
    // 注意：调用该方法前必须确认有足够的黄魂可扣
    public void decreaseGold(int num, int type, int subtype, boolean needSend, boolean isConsume) {
        if (num > 0) {
            int costGold1 = 0;
            int costGold2 = 0;
            int leftnum = num;
            if (gold2 > 0) {
                if (gold2 >= leftnum) {
                    costGold2 = leftnum;
                    gold2 -= leftnum;
                    leftnum = 0;
                } else {
                    costGold2 = gold2;
                    leftnum -= gold2;
                    gold2 = 0;
                }

                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildGold2Change(gold2));
                }
            }

            if (leftnum > 0) {
                costGold1 = leftnum;
                gold1 -= leftnum;
                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildGold1Change(gold1));
                }
            }

            if (costGold2 > 0 && costGold1 > 0) {
                if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_DECREASE) {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER , costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "GM", 0));
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER , costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "GM", 0));
                } else {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER , costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD , "" + type + ":" + subtype, 0));
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER , costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD , "" + type + ":" + subtype, 0));
                }
            } else if (costGold2 > 0) {
                if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_DECREASE) {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER, costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD, "GM", 0));
                } else {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER, costGold2, Consts.CONSUMER_LOG_TYPE_SYS_GOLD, "" + type + ":" + subtype, 0));
                }
            } else {
                if (type == Consts.SOUL_CHANGE_LOG_TYPE_GM_DECREASE) {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_GM_CONSUMER, costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD, "GM", 0));
                } else {
                    DBMessageQueue.queue().offer(MapDBMessageBuilder.buildConsumerLogDBMessage(id, Consts.CONSUMER_LOG_TYPE_CONSUMER, costGold1, Consts.CONSUMER_LOG_TYPE_CHARGE_GOLD, "" + type + ":" + subtype, 0));
                }
            }

            if (isConsume) {
                normalActivity.consumeGold(num);
            }

            if (MapConfig.INSTANCE.useCYLog == true) {
                List<String> cyLogList = new ArrayList<String>();
                cyLogList.add("commodityBuyMC");
                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                cyLogList.add("KDTY");
                cyLogList.add(String.valueOf(id));
                cyLogList.add(name);
                cyLogList.add("");
                cyLogList.add(String.valueOf(lv));
                cyLogList.add("1");
                cyLogList.add(String.valueOf(type));
                cyLogList.add("1");
                cyLogList.add("1");
                cyLogList.add(String.valueOf(num));
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("0");
                cyLogList.add("");
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_COMMODITY_BUY));
            }

            if (MapConfig.INSTANCE.useCYLog == true) {
                List<String> cyLogList = new ArrayList<String>();
                cyLogList.add("diamondMC");
                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                cyLogList.add("KDTY");
                cyLogList.add(String.valueOf(id));
                cyLogList.add(name);
                cyLogList.add("");
                cyLogList.add(String.valueOf(lv));
                cyLogList.add("1");
                cyLogList.add(String.valueOf(num));   
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("0");
                cyLogList.add("");
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_DIAMOND));
            }

            GameLogger.getlogger().log(GameLogMessageBuilder.buildDBGoldGameLogMessage(id, type, subtype, -costGold1, -costGold2, gold1, gold2, lv));
        }
    }

    public void buyToken(int num) {
        if ((num > 0) && (num <= MapConfig.INSTANCE.maxTokenNum)) {
            if (token < num) {
                int increaseNum = num - token;
                int needGold = increaseNum * MapConfig.INSTANCE.tokenPrice;
                if (getGold() >= needGold) {
                    decreaseGold(needGold, Consts.SOUL_CHANGE_LOG_TYPE_BUY_TOKEN, num, true, true);
                    increaseToken(increaseNum, true);

                    // 记录行为日志
                    if (MapConfig.INSTANCE.useCYLog == true) {
                        List<String> cyLogList = new ArrayList<String>();
                        cyLogList.add("behaviorMC");
                        cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                        cyLogList.add("KDTY");
                        cyLogList.add(String.valueOf(id));
                        cyLogList.add(name);
                        cyLogList.add("");
                        cyLogList.add("BuyTokenDBBehavior");
                        cyLogList.add(increaseNum + " " + token);
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                    }

                    GameLogger.getlogger().log(GameLogMessageBuilder.buildBuyTokenDBBehaviorGameLogMessage(id, increaseNum, token));
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't buy token[" + num + "] because not enough gold."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't buy token[" + num + "] because already has."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't buy token[" + num + "] because num error."));
        }
    }

    public void increaseToken(int num, boolean needSend) {
        if (num > 0) {
            if (token < MapConfig.INSTANCE.maxTokenNum) {
                token += num;
                if (token > MapConfig.INSTANCE.maxTokenNum) {
                    token = MapConfig.INSTANCE.maxTokenNum;
                }
                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildTokenChange(token));
                }
            }
        }
    }

    public void decreaseToken(int num, boolean needSend) {
        if (num > 0) {
            token -= num;
            if (needSend) {
                sendMessage(ClientToMapBuilder.buildTokenChange(token));
            }
        }
    }

    public void buyEnergy() {
        if (energy < HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy) {
            int needGold = 0;
            int currentDay = (int) ((GameServer.INSTANCE.getCurrentTime()+Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
            if (currentDay > lastBuyEnergyDay) {
                buyEnergyCount = 0;
                lastBuyEnergyDay = currentDay;
            }
            
            int pos = 0;
            VipNumGold[] vipNumGolds = MapConfig.INSTANCE.buyEnergyGolds;

            // 根据已使用次数查询对应的VipNumGold对象
            for (pos = 0; pos < vipNumGolds.length; pos++) {
                if (vipNumGolds[pos].num >= buyEnergyCount+1) {
                    break;
                }
            }

            if (pos < vipNumGolds.length) {
                needGold = (vipNumGolds[pos].vip > vip.level)?vipNumGolds[pos].gold:0;

                if (getGold() >= needGold) {
                    decreaseGold(needGold, Consts.SOUL_CHANGE_LOG_TYPE_BUY_ENERGY, Consts.SOUL_CHANGE_LOG_SUBTYPE_NONE, true, true);
                    increaseEnergy(Integer.MAX_VALUE, true);    // 补满体力
                    buyEnergyCount ++;
                    sendMessage(ClientToMapBuilder.buildBuyEnergy(buyEnergyCount,lastBuyEnergyDay));

                    // 记录行为日志
                    if (MapConfig.INSTANCE.useCYLog == true) {
                        List<String> cyLogList = new ArrayList<String>();
                        cyLogList.add("behaviorMC");
                        cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                        cyLogList.add("KDTY");
                        cyLogList.add(String.valueOf(id));
                        cyLogList.add(name);
                        cyLogList.add("");
                        cyLogList.add("BuyEnergyDBBehavior");
                        cyLogList.add(buyEnergyCount + " ");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        cyLogList.add("");
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                    }
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildBuyEnergyDBBehaviorGameLogMessage(id, buyEnergyCount));
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't buyEnergy because not enough gold"));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't buyEnergy because times limit"));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't buy energy because energy is full."));
        }
    }

    public void increaseEnergy(int num, boolean needSend) {
        if (num > 0) {
            int maxEnergy = HumanLevelsConfig.INSTANCE.levelConfigs[lv-1].maxEnergy;
            if (energy < maxEnergy) {
                energy += num;
                if ((energy <= 0) || (energy > maxEnergy)) {
                    energy = maxEnergy;
                }
                if (needSend) {
                    sendMessage(ClientToMapBuilder.buildEnergyChange(energy));
                }
            }
        }
    }

    public void decreaseEnergy(int num, boolean needSend) {
        if (num > 0) {
            energy -= num;
            if (needSend) {
                sendMessage(ClientToMapBuilder.buildEnergyChange(energy));
            }
        }
    }

    /**
     * 胜率计算（策划用）
     * @param battleId
     * @param helperCardId
     * @param helperCardLevel
     */
    public void calculateWinRate(int battleId, int helperCardId, int helperCardLevel) {
        PveBattleStaticInfo battleStaticInfo = PveBattlesConfig.INSTANCE.getPveBattleStaticInfo(battleId);

        if (battleStaticInfo != null) {
            CalculateWinRateBattle calculateWinRateBattle = new CalculateWinRateBattle();

            // 取出队长卡片数据
            Card leaderCard = sandbox.slots[sandbox.leader];
            TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

            // 助战者天赋
            CardStaticInfo helperCardStaticInfo = null;
            TalentStaticInfo helperTalentStaticInfo = null;
            if ((helperCardId > 0) && (helperCardLevel > 0)) {
                helperCardStaticInfo = CardFactories.INSTANCE.getCardFactory(helperCardId).staticInfo;

                if (helperCardStaticInfo.leaderTalentId != -1) {
                    helperTalentStaticInfo = TalentsConfig.INSTANCE.talentStaticInfos[helperCardStaticInfo.leaderTalentId];
                }
            }

            // 加入玩家战士
            float hpChange = (barrack != null)?1.0f+barrack.hpIncrease:1.0f;
            float atkChange = (ordnance != null)?1.0f+ordnance.atkIncrease:1.0f;
            int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
            int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
            for (int i=0; i<6; i++) {
                Card card = sandbox.slots[i];
                if (card != null) {
                    Fighter fighter = new Fighter(i, calculateWinRateBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                    calculateWinRateBattle.addFighter(fighter);
                }
            }

            // 加入助战者
            if ((helperCardId > 0) && (helperCardLevel > 0)) {
                Fighter fighter = new Fighter(sandbox.helper, calculateWinRateBattle, helperCardStaticInfo, helperCardLevel, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                calculateWinRateBattle.addFighter(fighter);
            }

            // 加入敌人
            for (PveBattleSlotEnemyConfig enemyConfig : battleStaticInfo.battleEnemySlots) {
                if (enemyConfig != null) {
                    assert ((enemyConfig.enemyPropabilitys != null) && (enemyConfig.enemyPropabilitys.length > 0));
                    Random random = RandomGenerator.INSTANCE.generator;
                    int tmp = random.nextInt(enemyConfig.enemyPropabilitys[enemyConfig.enemyPropabilitys.length-1].propabilityRange);
                    for (PveBattleSlotEnemyPropability enemyPropability : enemyConfig.enemyPropabilitys) {
                        if (tmp < enemyPropability.propabilityRange) {
                            Fighter fighter = new Fighter(enemyConfig.slotId, calculateWinRateBattle, CardFactories.INSTANCE.getCardFactory(enemyPropability.realId==0?enemyPropability.id:enemyPropability.realId).staticInfo, enemyPropability.level, Long.MAX_VALUE, null, null, enemyConfig.isBoss, 0, 1.0f, 1.0f, 0, 0);
                            calculateWinRateBattle.addFighter(fighter);
                            break;
                        }
                    }
                }
            }

            GameServer.INSTANCE.executeBattle(calculateWinRateBattle);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't calculate win rate because battle[" + battleId + "] not found."));
        }
    }

    /**
     * 产生战斗结果录像文件
     * @param battleId
     * @param helperCardId
     * @param helperCardLevel
     */
    public void generateBattleResult(int battleId, int helperCardId, int helperCardLevel, String outputFileName) {
        PveBattleStaticInfo battleStaticInfo = PveBattlesConfig.INSTANCE.getPveBattleStaticInfo(battleId);

        if (battleStaticInfo != null) {
            GenerateResultBattle generateResultBattle = new GenerateResultBattle(outputFileName);

            // 取出队长卡片数据
            Card leaderCard = sandbox.slots[sandbox.leader];
            TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

            // 助战者天赋
            CardStaticInfo helperCardStaticInfo = null;
            TalentStaticInfo helperTalentStaticInfo = null;
            if ((helperCardId > 0) && (helperCardLevel > 0)) {
                helperCardStaticInfo = CardFactories.INSTANCE.getCardFactory(helperCardId).staticInfo;

                if (helperCardStaticInfo.leaderTalentId != -1) {
                    helperTalentStaticInfo = TalentsConfig.INSTANCE.talentStaticInfos[helperCardStaticInfo.leaderTalentId];
                }
            }

            float hpChange = (barrack != null)?1.0f+barrack.hpIncrease:1.0f;
            float atkChange = (ordnance != null)?1.0f+ordnance.atkIncrease:1.0f;
            int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
            int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
            // 加入玩家战士
            for (int i=0; i<6; i++) {
                Card card = sandbox.slots[i];
                if (card != null) {
                    Fighter fighter = new Fighter(i, generateResultBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                    generateResultBattle.addFighter(fighter);
                }
            }

            // 加入助战者
            if ((helperCardId > 0) && (helperCardLevel > 0)) {
                Fighter fighter = new Fighter(sandbox.helper, generateResultBattle, helperCardStaticInfo, helperCardLevel, Long.MAX_VALUE, leaderTalentStaticInfo, helperTalentStaticInfo, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                generateResultBattle.addFighter(fighter);
            }

            // 加入敌人
            for (PveBattleSlotEnemyConfig enemyConfig : battleStaticInfo.battleEnemySlots) {
                if (enemyConfig != null) {
                    assert ((enemyConfig.enemyPropabilitys != null) && (enemyConfig.enemyPropabilitys.length > 0));
                    Random random = RandomGenerator.INSTANCE.generator;
                    int tmp = random.nextInt(enemyConfig.enemyPropabilitys[enemyConfig.enemyPropabilitys.length-1].propabilityRange);
                    for (PveBattleSlotEnemyPropability enemyPropability : enemyConfig.enemyPropabilitys) {
                        if (tmp < enemyPropability.propabilityRange) {
                            Fighter fighter = new Fighter(enemyConfig.slotId, generateResultBattle, CardFactories.INSTANCE.getCardFactory(enemyPropability.realId==0?enemyPropability.id:enemyPropability.realId).staticInfo, enemyPropability.level, Long.MAX_VALUE, null, null, enemyConfig.isBoss, 1, 1.0f, 1.0f, 0, 0);
                            generateResultBattle.addFighter(fighter);
                            break;
                        }
                    }
                }
            }

            GameServer.INSTANCE.executeBattle(generateResultBattle);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't generate battle result because battle[" + battleId + "] not found."));
        }
    }

    public void startPveBattle() {
        if (stage != null) {
            if (!stage.isCurrentBattleExecuting) {
                if (!stage.isCurrentBattleFinished) {
                    if (stage.currentBattleIndex != -1) {
                        if (!stage.needRevive) {
                            if (GameServer.INSTANCE.getCurrentTime() >= nextBattlePermitTime) {
                                PveBattle pveBattle = stage.createPveBattle();

                                GameServer.INSTANCE.executeBattle(pveBattle);

                                stage.isCurrentBattleExecuting = true;
                            } else {
                                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                        "Player[" + id + "] can't startOnlyOnce battle because last battle is fighting."));
                            }
                        } else {
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                    "Player[" + id + "] can't startOnlyOnce battle because need revive."));
                        }
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + id + "] can't startOnlyOnce battle because no more battle."));
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't startOnlyOnce battle because battle is finished."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_DEBUG,
                        "Player[" + id + "] can't startOnlyOnce battle because battle is executing."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't startOnlyOnce battle out of stage."));
        }
    }

    public void digestCertainReward(CertainRewardInfo rewardInfo, int type, int subType) {
        if (rewardInfo.items != null) {
            for (RewardItemInfo rewardItemInfo : rewardInfo.items) {
                switch (rewardItemInfo.itemType) {
                    case Consts.REWARD_ITEM_TYPE_CARD: {
                        cards.addCard(rewardItemInfo.itemId, rewardItemInfo.level, 0, true);
                        break;
                    }
                    case Consts.REWARD_ITEM_TYPE_ITEM: {
                        items.addItem(rewardItemInfo.itemId, rewardItemInfo.num, true);
                        break;
                    }
                    case Consts.REWARD_ITEM_TYPE_GOLD: {
                        increaseGold(0, rewardItemInfo.num, type, subType, true);
                        break;
                    }
                    case Consts.REWARD_ITEM_TYPE_SILVER: {
                        increaseSilver(rewardItemInfo.num, type, subType, true);
                        break;
                    }
                }
            }
        }
        
        increaseExperience(rewardInfo.experience, type, subType, true);
        increaseEnergy(rewardInfo.energy, true);
        increaseSilver(rewardInfo.silver, type, subType, true);
        increaseGold(0, rewardInfo.gold, type, subType, true);
    }
    
    private void digestStageBox(boolean needSend) {
        StageBox box = stage.box;

        if (box.experience > 0) {
            increaseExperience(box.experience, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
        }

        if (box.gold > 0) {
            increaseGold(0, box.gold, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
        }

        if (box.silver > 0) {
            increaseSilver(box.silver, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
        }
        
        if (box.items != null) {
            for (RewardItemInfo rewardItemInfo : box.items) {
                switch (rewardItemInfo.itemType) {
                    case Consts.REWARD_ITEM_TYPE_CARD: {
                        cards.addCard(rewardItemInfo.itemId, rewardItemInfo.level, 0, needSend);
                        break;
                    }
                    case Consts.REWARD_ITEM_TYPE_ITEM: {
                        items.addItem(rewardItemInfo.itemId, rewardItemInfo.num, needSend);
                        break;
                    }
                    case Consts.REWARD_ITEM_TYPE_GOLD: {
                        increaseGold(0, rewardItemInfo.num, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
                        break;
                    }
                    case Consts.REWARD_ITEM_TYPE_SILVER: {
                        increaseSilver(rewardItemInfo.num, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_PVE, stage.staticInfo.id, needSend);
                        break;
                    }
                }
            }
        }
    }

    public void receivePveBattleResult(int stageId, int battleId, LinkedList<RewardItemInfo> rewardItemInfos, BattleResultProto battleResult) {
        if (stage != null) {
            if (stage.isCurrentBattleExecuting) {
                if (stage.staticInfo.id == stageId) {
                    if (stage.currentBattleIndex == battleId) {
                        stage.isCurrentBattleExecuting = false;

                        if (battleResult.getWinner() == 0) {  // 战斗胜利
                            // 累计战斗掉落
                            stage.box.addItems(rewardItemInfos);
                            stage.isCurrentBattleFinished = true;
                        } else {
                            stage.needRevive = true;
                        }

                        sendMessage(ClientToMapBuilder.buildPveBattleResult(battleResult));

                        nextBattlePermitTime = GameServer.INSTANCE.getCurrentTime() + Consts.MILSECOND_1SECOND;
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + id + "] get battle[" + battleId + "] result of stage[" + stageId + "] but is waiting for battle[" + stage.currentBattleIndex + "]."));
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] get battle[" + battleId + "] result of stage[" + stageId + "] in different stage[" + stage.staticInfo.id + "]."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] get battle[" + battleId + "] result of stage[" + stageId + "] but no battle is running."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] get battle[" + battleId + "] result out of stage[" + stageId + "]."));
        }
    }

    // 升级
    public void levelup(int upLevel, boolean needSend) {
        int oldLv = lv;
        lv += upLevel;

        // 补满体力
        increaseEnergy(Integer.MAX_VALUE, needSend);

        // 补满军令
        increaseToken(MapConfig.INSTANCE.maxTokenNum, needSend);

        GameServer.INSTANCE.briefPlayerInfos.levelupPlayer(id, lv);

        quests.levelup(lv);

        if (needSend) {
            sendMessage(ClientToMapBuilder.buildLevelup(lv));
        }

        // 调整等级列表数据
        PlayerIdsOfLevels.INSTANCE.removePlayerId(oldLv, id);
        PlayerIdsOfLevels.INSTANCE.addPlayerId(lv, id);

        // 更新服中最大玩家等级
        if (lv > GameServer.INSTANCE.maxHumanLevel) {
            GameServer.INSTANCE.maxHumanLevel = lv;
        }

        if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
            if (hegemonyTargets == null) {
                lastHegemonyPayDay = (int) ((GameServer.INSTANCE.getCurrentTime()+Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
                hegemonyTargets = new HegemonyTargets(this, null);

                // 通知客户端争霸列表
                sendMessage(ClientToMapBuilder.buildHegemonyTargetsChange(hegemonyTargets.buildHegemonyTargetsProto()));
            }
        }

        if (lv >= MapConfig.INSTANCE.openMineLevel) {
            // 若臣属数据不在内存，加载之
            OccupyInfo occupyInfo = OccupyInfos.INSTANCE.getOccupyInfo(id);
            if (occupyInfo == null) {
                OccupyInfos.INSTANCE.loadOccupyInfoFromDB(id);
            } else if (occupyInfo.inited) {
                occupyInfo.level = lv;
            }
        }

        if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
            if (training == null) {
                training = new Training(this, null);
            }
        }

        // 银矿
        if (lv >=MapConfig.INSTANCE.openMineLevel) {
            if (mine == null) {
                mine = new Mine(this, null);
            }

            // 刷新银矿产量值
            ServerMessageQueue.queue().offer(MapMessageBuilder.buildBaseMineProductionChangeMessage(id, mine.getProduction()));
        }

        // 兵营
        if (lv >=MapConfig.INSTANCE.openBarrackLevel) {
            if (barrack == null) {
                barrack = new Barrack(this, null);
            }
        }

        // 军械所
        if (lv >=MapConfig.INSTANCE.openOrdnanceLevel) {
            if (ordnance == null) {
                ordnance = new Ordnance(this, null);
            }
        }

        // 军机处
        if (lv >=MapConfig.INSTANCE.openCouncilLevel) {
            if (council == null) {
                council = new Council(this, null);
            }
        }

        // 通知朋友等级改变
        broadcastToFriends(ClientToMapBuilder.buildFriendLevelChange(id, lv));

        if (MapConfig.INSTANCE.useCYLog == true) {
            List<String> cyLogList = new ArrayList<String>();
            cyLogList.add("roleMC");
            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
            cyLogList.add("KDTY");
            cyLogList.add(String.valueOf(id));
            cyLogList.add(name);
            cyLogList.add("");
            cyLogList.add(String.valueOf(lv));
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_ROLE));

            cyLogList = new ArrayList<String>();
            cyLogList.add("behaviorMC");
            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
            cyLogList.add("KDTY");
            cyLogList.add(String.valueOf(id));
            cyLogList.add(name);
            cyLogList.add("");
            cyLogList.add("LevelupDBBehavior");
            cyLogList.add(oldLv + " " + lv);
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
        }
        GameLogger.getlogger().log(GameLogMessageBuilder.buildLevelupDBBehaviorGameLogMessage(id, oldLv, lv));
    }

    // 升军衔
    public void rankLevelup(int upLevel, boolean needSend) {
        int oldRankLv = rankLv;
        rankLv += upLevel;

        if (lv >= MapConfig.INSTANCE.openMineLevel) {
            // 若臣属数据不在内存，加载之
            OccupyInfo occupyInfo = OccupyInfos.INSTANCE.getOccupyInfo(id);
            if (occupyInfo == null) {
                OccupyInfos.INSTANCE.loadOccupyInfoFromDB(id);
            } else if (occupyInfo.inited) {
                occupyInfo.rank = rankLv;
            }
        }

        // 调整军衔列表数据
        PlayerIdsOfRanks.INSTANCE.removePlayerId(oldRankLv, id);
        PlayerIdsOfRanks.INSTANCE.addPlayerId(rankLv, id);

        // 刷新最高战斗力
        checkMaxPowerChange();

        if (needSend) {
            sendMessage(ClientToMapBuilder.buildRankLevelup(rankLv));
        }
        
        if (MapConfig.INSTANCE.useCYLog == true) {
            List<String> cyLogList = new ArrayList<String>();
            cyLogList.add("behaviorMC");
            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
            cyLogList.add("KDTY");
            cyLogList.add(String.valueOf(id));
            cyLogList.add(name);
            cyLogList.add("");
            cyLogList.add("RankLevelupDBBehavior");
            cyLogList.add(oldRankLv + " " + rankLv);
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
        }

        GameLogger.getlogger().log(GameLogMessageBuilder.buildRankLevelupDBBehaviorGameLogMessage(id, oldRankLv, rankLv));
    }

    public void update(int difftime) {
        flushTimer.update(difftime); // 数据库更新计时器
    }

    public void enterGame() {
        // 修改简略玩家信息的上线标志
        if (!GameServer.INSTANCE.briefPlayerInfos.setInGame(id)) {
            Card leaderCard = sandbox.slots[sandbox.leader];
            GameServer.INSTANCE.briefPlayerInfos.addBriefPlayerInfo(id, name, lv, leaderCard.staticInfo.id, leaderCard.level, true);
        }

        enterTime = GameServer.INSTANCE.getCurrentTime();
        timeRefresh();
        contSign.sign(false);

        updateTimer = new HumanUpdateTimer();
        // 返回进入游戏角色信息给客户端
        sendMessage(ClientToMapBuilder.buildEnterGameRet(humanProtocolBuilder.buildEnterGameCharProto()));

        Bill bill = new Bill(id, mapPlayer.passport);
        GameServer.INSTANCE.executeBill(bill);
        NotifySystem.INSTANCE.sendAllHumanNotes(this);

        // 获取关系信息
        GameServer.INSTANCE.social.loadRelation(this);

        // 刷新补偿信息
        mails.refresh();

        flushTimer = new FlushDataTimer(mapPlayer);

        // inGame标志在最后设置是因为上面timeRefresh中会发通知（在onEnterGame发包之前），通知系统中会根据inGame标志判断是否立即发包
        inGame = true;

        ip = mapPlayer.channelContext.getRemoteIP();

        // 写登陆日志
        if (MapConfig.INSTANCE.useCYLog == true){
            List<String> cyLogList = new ArrayList<String>();
            cyLogList.add("loginMC");
            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
            cyLogList.add("KDTY");
            cyLogList.add(String.valueOf(id));
            cyLogList.add(name);
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add(String.valueOf(0));
            cyLogList.add("");
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_LOGIN));

            cyLogList = new ArrayList<String>();
            cyLogList.add("userMC");
            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
            cyLogList.add("KDTY");
            cyLogList.add(String.valueOf(id));
            cyLogList.add(name);
            cyLogList.add(String.valueOf(lv));
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add("");
            cyLogList.add(String.valueOf(0));
            cyLogList.add("");
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_USER));
        }
        
        GameLogger.getlogger().log(GameLogMessageBuilder.buildDBLoginLogoutGameLogMessage(id, lv, true, ip, 0));

        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_DEBUG,
                "Player["+id+"] enter game."));
    }

    public void leaveGame() {
        if (inGame) {
            updateTimer = null;

            // 清空副本和挑战
            if (stage != null) {
                if (stage.isCurrentBattleFinished) {
                    stageContinue(false);
                } else {
                    stage.isCurrentBattleExecuting = false;
                }
            }

            // 复位争霸战斗状态
            if (hegemonyTargets != null) {
                hegemonyTargets.isFighting = false;
            }

            // 复位据点战斗状态
            if (baseTargets != null) {
                if (baseTargets.fightingOccupyInfo != null) {
                    baseTargets.fightingOccupyInfo.fighting = false;
                    baseTargets.fightingOccupyInfo.waitUpWaitingMessage();
                    baseTargets.fightingOccupyInfo = null;
                }
            }
            
            // 复位反抗状态
            if (selfOccupyInfo != null) {
                selfOccupyInfo.fighting = false;
                selfOccupyInfo.waitUpWaitingMessage();
                selfOccupyInfo = null;
            }

            leaveTime = GameServer.INSTANCE.getCurrentTime();
            totalOnlineTime += leaveTime - enterTime;
            mapPlayer = null;

            if (relation != null) {
                // 广播通知follower玩家离线
                if (!relation.friends.isEmpty()) {
                    ProtobufMessage protobufMessage = ClientToMapBuilder.buildFriendLeft(id);
                    for (Integer friendId : relation.friends.keySet()) {
                        MapPlayer friendPlayer = GameServer.INSTANCE.players.get(friendId);
                        if ((friendPlayer != null) && (friendPlayer.human != null) && (friendPlayer.human.inGame)) {
                            friendPlayer.human.sendMessage(protobufMessage);
                        }
                    }
                }

                // 清理好友关系
                relation.human = null;
                relation = null;
            }

            // 玩家数据入库
            flushData();

            inGame = false;

            // 修改简略玩家信息的上线标志
            GameServer.INSTANCE.briefPlayerInfos.setOffGame(id);

            // 写登出日志
            if (MapConfig.INSTANCE.useCYLog == true) {
                List<String> cyLogList = new ArrayList<String>();
                cyLogList.add("onlineTimeMC");
                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                cyLogList.add("KDTY");
                cyLogList.add(String.valueOf(id));
                cyLogList.add(name);                
                cyLogList.add(String.valueOf((leaveTime - enterTime)/Consts.MILSECOND_1MINITE));
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_ONLINE_TIME));
            }

            GameLogger.getlogger().log(GameLogMessageBuilder.buildDBLoginLogoutGameLogMessage(id, lv, false, ip, leaveTime - enterTime));
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR, "Player[" + id + "] multi-logout!"));
        }
    }

    public void enterActivityStage(int stageId, int helper, int activityId, int activityItemId) {
        if (stage == null) {
            // 判断卡槽是否满
            if (cards.cards.size() < HumanLevelsConfig.INSTANCE.levelConfigs[lv - 1].baseCardNum + MapConfig.INSTANCE.vipCardSlotNums[vip.level]) {
                StageStaticInfo[] stageStaticInfos = StagesConfig.INSTANCE.activityStageStaticInfos;
                if ((stageId >= 0) && (stageId < stageStaticInfos.length)) {
                    StageStaticInfo stageStaticInfo = stageStaticInfos[stageId];
                    // 判断等级限制
                    if (lv >= stageStaticInfo.levelLimit) {
                        // 判断体力是否满足
                        if (energy >= stageStaticInfo.energyCost) {
                            // 校验助战者
                            BriefPlayerInfo helperInfo = (helper != 0)?getHelperBriefPlayerInfo(helper):null;

                            stage = new ActivityStage(this, stageStaticInfo, helperInfo, activityId, activityItemId);

                            // 通知客户端进入副本
                            sendMessage(ClientToMapBuilder.buildStageState(stage.buildStageStateProto()));

                            // 记录行为日志
                            if (MapConfig.INSTANCE.useCYLog == true) {
                                List<String> cyLogList = new ArrayList<String>();
                                cyLogList.add("behaviorMC");
                                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                                cyLogList.add("KDTY");
                                cyLogList.add(String.valueOf(id));
                                cyLogList.add(name);
                                cyLogList.add("");
                                cyLogList.add("EnterStageDBBehavior");
                                cyLogList.add(Consts.STAGE_TYPE_ACTIVITY + " " + stageId);
                                cyLogList.add("");
                                cyLogList.add("");
                                cyLogList.add("");
                                cyLogList.add("");
                                cyLogList.add("");
                                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                            }

                            GameLogger.getlogger().log(GameLogMessageBuilder.buildEnterStageDBBehaviorGameLogMessage(id, Consts.STAGE_TYPE_ACTIVITY, stageId, (helperInfo!=null)?helperInfo.leaderCardId:0, (helperInfo!=null)?helperInfo.leaderCardLevel:0, sandbox.buildSandboxProto().toByteArray()));
                        } else {
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                    "Player[" + id + "] can't enter activity stage["+stageId+"] because not enough energy."));
                        }
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + id + "] can't enter activity stage["+stageId+"] because level limit."));
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't enter activity stage["+stageId+"] because stage not exist."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't enter activity stage["+stageId+"] because card slots are full."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't enter activity stage["+stageId+"] when in other stage."));
        }
    }

    /**
     * 进入副本
     */
    public void enterStage(int stageId, boolean isBigStage, int helper) {
        // 判断是否已经在副本中
        if (stage == null) {
            // 判断卡槽是否满
            if (cards.cards.size() < HumanLevelsConfig.INSTANCE.levelConfigs[lv - 1].baseCardNum + MapConfig.INSTANCE.vipCardSlotNums[vip.level]) {
                // 根据类型判断副本是否存在
                StageStaticInfo[] stageStaticInfos = (isBigStage)?StagesConfig.INSTANCE.bigStageStaticInfos:StagesConfig.INSTANCE.normalStageStaticInfos;
                if ((stageId >= 0) && (stageId < stageStaticInfos.length)) {
                    StageStaticInfo stageStaticInfo = stageStaticInfos[stageId];
                    // 判断等级限制
                    if (lv >= stageStaticInfo.levelLimit) {
                        // 判断体力是否满足
                        if (energy >= stageStaticInfo.energyCost) {
                            // 若是精英副本，每天只允许进一次
                            if (isBigStage) {
                                if (!stages.isStagePassed(stageStaticInfo.normalId, false)) {
                                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                            "Player[" + id + "] can't enter big stage["+stageId+"] because normal state[" + stageStaticInfo.normalId + "] not pass."));

                                    return;
                                } else if (!stages.canEnterBigStage(stageId)) {
                                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                            "Player[" + id + "] can't enter big stage["+stageId+"] more than one times in a day."));

                                    return;
                                }
                            }

                            // 校验助战者
                            BriefPlayerInfo helperInfo = (helper != 0)?getHelperBriefPlayerInfo(helper):null;

                            stage = new Stage(this, stageStaticInfo, helperInfo);

                            // 通知客户端进入副本
                            sendMessage(ClientToMapBuilder.buildStageState(stage.buildStageStateProto()));

                            // 记录行为日志
                            if (MapConfig.INSTANCE.useCYLog == true) {
                                List<String> cyLogList = new ArrayList<String>();
                                cyLogList.add("behaviorMC");
                                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                                cyLogList.add("KDTY");
                                cyLogList.add(String.valueOf(id));
                                cyLogList.add(name);
                                cyLogList.add("");
                                cyLogList.add("EnterStageDBBehavior");
                                cyLogList.add((isBigStage ? Consts.STAGE_TYPE_BIG : Consts.STAGE_TYPE_NORMAL) + " " + stageId);
                                cyLogList.add("");
                                cyLogList.add("");
                                cyLogList.add("");
                                cyLogList.add("");
                                cyLogList.add("");
                                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                            }
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildEnterStageDBBehaviorGameLogMessage(id, isBigStage?Consts.STAGE_TYPE_BIG:Consts.STAGE_TYPE_NORMAL, stageId, (helperInfo!=null)?helperInfo.leaderCardId:0, (helperInfo!=null)?helperInfo.leaderCardLevel:0, sandbox.buildSandboxProto().toByteArray()));
                        } else {
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                    "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + " stage["+stageId+"] because not enough energy."));
                        }
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + " stage["+stageId+"] because level limit."));
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't enter unknown " + (isBigStage?"big":"normal") + " stage["+stageId+"]."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + " stage["+stageId+"] because card slots are full."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't enter " + (isBigStage?"big":"normal") + "stage["+stageId+"] when in other stage."));
        }
    }

    private BriefPlayerInfo getHelperBriefPlayerInfo(int helper) {
        // 先从陌生人中查询
        for (BriefPlayerInfo briefPlayerInfo : strangers) {
            if (briefPlayerInfo.id == helper) {
                return briefPlayerInfo;
            }
        }

        // 再从朋友中查询
        if (relation != null) {
            Long permitTime = relation.friends.get(helper);
            if ((permitTime != null) && (permitTime <= GameServer.INSTANCE.getCurrentTime())) {
                return GameServer.INSTANCE.briefPlayerInfos.get(helper);
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't select friend["+helper+"] because not cooldown."));
            }
        }

        return null;
    }

    public long nextAllowGetCardDrawActivityListTime;   // 下一次获取商城活动操作许可时间（防止被攻击）
    public void getCardDrawActivityList() {
        long currentTime = GameServer.INSTANCE.getCurrentTime();
        if (currentTime >= nextAllowGetCardDrawActivityListTime) {
            nextAllowGetCardDrawActivityListTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
            sendMessage(ClientToMapBuilder.buildCardDrawActivityList(CardDrawActivityTemplates.INSTANCE.buildCardDrawActivitiesProto()));
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] get card-draw activity list error because not cooldown."));
        }
    }

    public long nextAllowGetStageActivityListTime;   // 下一次获取关卡活动操作许可时间（防止被攻击）
    public void getStageActivityList() {
        long currentTime = GameServer.INSTANCE.getCurrentTime();
        if (currentTime >= nextAllowGetStageActivityListTime) {
            nextAllowGetStageActivityListTime = currentTime + Consts.MILSECOND_1SECOND;  // cooldown 1 second
            sendMessage(ClientToMapBuilder.buildStageActivityList(StageActivityTemplates.INSTANCE.buildStageActivitiesProto()));
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] get stage activity list error because not cooldown."));
        }
    }

    public void changeSandbox(SandboxProto sandboxProto) {
        if (stage != null) {
            sandbox.littleChange(sandboxProto);
        } else {
            sandbox.change(sandboxProto);
        }
    }

    public void changeTraining(IntValuesProto intValuesProto) {
        if (lv >= MapConfig.INSTANCE.openTrainingLevel) {
            training.change(intValuesProto);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't change training because level limit."));
        }
    }

    public void changeBarrack(IntValuesProto intValuesProto) {
        if (lv >= MapConfig.INSTANCE.openBarrackLevel) {
            barrack.change(intValuesProto);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't change barrack because level limit."));
        }
    }

    public void changeOrdnance(IntValuesProto intValuesProto) {
        if (lv >= MapConfig.INSTANCE.openOrdnanceLevel) {
            ordnance.change(intValuesProto);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't change ordnance because level limit."));
        }
    }

    public void changeCouncil(IntValuesProto intValuesProto) {
        if (lv >= MapConfig.INSTANCE.openCouncilLevel) {
            council.change(intValuesProto);
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't change council because level limit."));
        }
    }

    public void stageContinue(boolean needSend) {
        // 向客户端发当前副本状态
        if (stage != null) {
            if (!stage.isStageFinished) {
                if (stage.isCurrentBattleFinished) {
                    // 计算下一场战斗阵型
                    stage.moveNext();

                    if (needSend) {
                        sendMessage(ClientToMapBuilder.buildStageState(stage.buildStageStateProto()));
                    }

                    if (stage.isStageFinished) {
                        // 扣体力，加掉落获得，完成并离开副本
                        // 判断是否有体力减半活动
                        if (StageActivityTemplates.INSTANCE.halfEnergy(stage.staticInfo.id)) {
                            decreaseEnergy((stage.staticInfo.energyCost+1)/2, needSend);    // 策划要求上取整
                        } else {
                            decreaseEnergy(stage.staticInfo.energyCost, needSend);
                        }

                        digestStageBox(needSend);

                        switch (stage.staticInfo.type) {
                            case Consts.STAGE_TYPE_NORMAL: {
                                stages.finishState(stage.staticInfo.id, false, needSend);
                                break;
                            }
                            case Consts.STAGE_TYPE_BIG: {
                                stages.finishState(stage.staticInfo.id, true, needSend);
                                break;
                            }
                            case Consts.STAGE_TYPE_ACTIVITY: {
                                ActivityStage activityStage = (ActivityStage)stage;
                                normalActivity.finishState(activityStage.activityId, activityStage.activityItemId);
                                break;
                            }
                        }

                        // 若助战者是好友，设置冷却
                        if (stage.helperInfo != null) {
                            if (relation != null) {
                                if (relation.friends.containsKey(stage.helperInfo.id)) {
                                    long cooldownTime = GameServer.INSTANCE.getCurrentTime() + Consts.FRIEND_HELP_COOLDOWN_TIME;
                                    relation.friends.put(stage.helperInfo.id, cooldownTime);

                                    if (needSend) {
                                        sendMessage(ClientToMapBuilder.buildFriendHelpCooldown(stage.helperInfo.id, cooldownTime));
                                    }
                                }
                            }
                        }

                        // 重新生成陌生人表
                        generateStrangers(needSend);

                        if (needSend) {
                            if (stage.staticInfo.type != Consts.STAGE_TYPE_ACTIVITY) {
                                sendMessage(ClientToMapBuilder.buildLeaveStage(stage.staticInfo.id, stage.staticInfo.type));
                            } else {
                                ActivityStage activityStage = (ActivityStage)stage;
                                sendMessage(ClientToMapBuilder.buildLeaveStage(activityStage.activityId, Consts.STAGE_TYPE_ACTIVITY));
                            }
                        }

                        // 记录行为日志
                        if (MapConfig.INSTANCE.useCYLog == true) {
                            List<String> cyLogList = new ArrayList<String>();
                            cyLogList.add("instanceMC");
                            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                            cyLogList.add("KDTY");
                            cyLogList.add(String.valueOf(id));
                            cyLogList.add(name);
                            cyLogList.add("");
                            cyLogList.add(String.valueOf(lv));
                            cyLogList.add(String.valueOf(stage.staticInfo.type));
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_INSTANCE));

                            cyLogList = new ArrayList<String>();
                            cyLogList.add("behaviorMC");
                            cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                            cyLogList.add("KDTY");
                            cyLogList.add(String.valueOf(id));
                            cyLogList.add(name);
                            cyLogList.add("");
                            cyLogList.add("FinishStageDBBehavior");
                            cyLogList.add(stage.staticInfo.type + " " + stage.staticInfo.id);
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            cyLogList.add("");
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                        }

                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFinishStageDBBehaviorGameLogMessage(id, stage.staticInfo.type, stage.staticInfo.id));
                        stage = null;
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't continue stage because current battle not finish."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't continue stage because stage is finished."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't continue stage out of stage."));
        }
    }

    /**
     * 离开副本
     */
    public void leaveStage() {
        if (stage != null) {
            if (stage.needRevive) {
                if (stage.staticInfo.type != Consts.STAGE_TYPE_ACTIVITY) {
                    sendMessage(ClientToMapBuilder.buildLeaveStage(stage.staticInfo.id, stage.staticInfo.type));
                } else {
                    ActivityStage activityStage = (ActivityStage)stage;
                    sendMessage(ClientToMapBuilder.buildLeaveStage(activityStage.activityId, Consts.STAGE_TYPE_ACTIVITY));
                }

                // 记录行为日志
                if (MapConfig.INSTANCE.useCYLog == true) {
                    List<String> cyLogList = new ArrayList<String>();
                    cyLogList.add("behaviorMC");
                    cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                    cyLogList.add("KDTY");
                    cyLogList.add(String.valueOf(id));
                    cyLogList.add(name);
                    cyLogList.add("");
                    cyLogList.add("LeaveStageDBBehavior");
                    cyLogList.add(stage.staticInfo.type + " " + stage.staticInfo.id);
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    cyLogList.add("");
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                }
                GameLogger.getlogger().log(GameLogMessageBuilder.buildLeaveStageDBBehaviorGameLogMessage(id, stage.staticInfo.type, stage.staticInfo.id));

                stage = null;
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't leave stage because not dead."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't leave stage because not in stage."));
        }
    }

    /**
     * 关卡中复活
     */
    public void reviveStage() {
        if (stage != null) {
            stage.revive();
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't revive stage because not in stage."));
        }
    }

    public void striveForHegemony(int targetSlot, boolean stimulate) {
        if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
            if (!hegemonyTargets.isFighting) {
                if (GameServer.INSTANCE.getCurrentTime() >= nextBattlePermitTime) {
                    if ((targetSlot >=0) && (targetSlot < Consts.MAX_HEGEMONY_TARGET_NUM)) {
                        if ((!stimulate && (token > 0)) || (stimulate && (token >= 3))) {
                            HegemonyTarget target = hegemonyTargets.targets[targetSlot];

                            if (target.status != Consts.HEGEMONY_TARGET_STATUS_WIN) {
                                // 扣军令
                                if (stimulate) {
                                    decreaseToken(3, true);
                                } else {
                                    decreaseToken(1, true);
                                }

                                // 产生战斗，并进行计算
                                HegemonyBattle hegemonyBattle = createHegemonyBattle(targetSlot, stimulate);

                                GameServer.INSTANCE.executeBattle(hegemonyBattle);

                                hegemonyTargets.isFighting = true;
                            } else {
                                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                        "Player[" + id + "] can't strive for hegemony because target slot[" + targetSlot + "] had win."));
                            }
                        } else {
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                    "Player[" + id + "] can't strive for hegemony because no token."));
                        }
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + id + "] can't strive for hegemony because target slot[" + targetSlot + "] not exist."));
                    }
                } else {
                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                            FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                            "Player[" + id + "] can't strive for hegemony because because last battle is fighting."));
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't strive for hegemony because is fighting."));
            }
        } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't strive for hegemony because level limit."));
        }
    }

    public HegemonyBattle createHegemonyBattle(int targetSlot, boolean stimulate) {
        HegemonyTarget target = hegemonyTargets.targets[targetSlot];
        HegemonyBattle hegemonyBattle = new HegemonyBattle(id, targetSlot, target.power, stimulate);

        // 取出队长卡片数据
        Card leaderCard = sandbox.slots[sandbox.leader];
        TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

        float hpChange = (stimulate?0.5f:0) + ((barrack != null)?1.0f+barrack.hpIncrease:1.0f);
        float atkChange = (stimulate?0.5f:0) + ((ordnance != null)?1.0f+ordnance.atkIncrease:1.0f);
        int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
        int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
        // 加入玩家战士
        for (int i=0; i<Consts.MAX_SANDBOX_SLOT_NUM; i++) {
            Card card = sandbox.slots[i];
            if (card != null) {
                Fighter fighter = new Fighter(i, hegemonyBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, null, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                hegemonyBattle.addFighter(fighter);
            }
        }

        // 取出对手队长卡片数据
        TargetSandbox targetSandbox = target.sandbox;
        CardStaticInfo targetLeaderCardStaticInfo = CardFactories.INSTANCE.getCardFactory(targetSandbox.slots[targetSandbox.leader].cardId).staticInfo;
        TalentStaticInfo targetLeaderTalentStaticInfo = (targetLeaderCardStaticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[targetLeaderCardStaticInfo.leaderTalentId]:null;

        // 加入对手战士，并计算对手总战力
        float targetHpChange = target.hpIncrease + 1.0f;
        float targetAtkChange = target.atkIncrease + 1.0f;
        int targetCriAndTenChange = target.criAndTenIncrease;
        int targetHitAndDodChange = target.hitAndDodIncrease;
        for (int i=0; i<Consts.MAX_SANDBOX_SLOT_NUM; i++) {
            TargetSandboxCard targetCard = targetSandbox.slots[i];
            if (targetCard != null) {
                CardStaticInfo cardStaticInfo = CardFactories.INSTANCE.getCardFactory(targetCard.cardId).staticInfo;
                Fighter fighter = new Fighter(Consts.MAX_SANDBOX_SLOT_NUM + i, hegemonyBattle, cardStaticInfo, targetCard.cardLevel, Long.MAX_VALUE, targetLeaderTalentStaticInfo, null, false, 0, targetHpChange, targetAtkChange, targetCriAndTenChange, targetHitAndDodChange);
                hegemonyBattle.addFighter(fighter);
            }
        }
        
        return hegemonyBattle;
    }

    public void receiveHegemonyBattleResult(int targetSlot, int targetPower, boolean stimulate, BattleResultProto battleResult) {
        if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
            if (hegemonyTargets.isFighting) {
                HegemonyTarget target = hegemonyTargets.targets[targetSlot];
                // 取消战斗状态
                hegemonyTargets.isFighting = false;

                nextBattlePermitTime = GameServer.INSTANCE.getCurrentTime() + Consts.MILSECOND_1SECOND;

                // 计算战斗奖励及更新状态
                int rewardSilver = 0;
                int rewardRankExp = 0;
                int oldStatus = target.status;
                int cardDrawId = -1;
                CardDrawItem cardDrawItem = null;
                HumanRankConfig humanRankConfig = HumanRanksConfig.INSTANCE.rankConfigs[target.rank-1];
                if (battleResult.getWinner() == 0) {    // 战斗胜利
                    target.status = Consts.HEGEMONY_TARGET_STATUS_WIN;

                    rewardSilver = (int) (targetPower * humanRankConfig.hegemonySilverCoef);
                    rewardRankExp = (int) (targetPower * humanRankConfig.hegemonyRankExpCoef);

                    // 统计胜利场数，决定是否开卡包
                    int winNum = hegemonyTargets.getWinNum();
                    if (winNum == Consts.MAX_HEGEMONY_TARGET_NUM) {
                        // 全胜开大卡包
                        cardDrawId = MapConfig.INSTANCE.hegemonyBigCardDrawId;
                        CardDrawStaticInfo cardDrawStaticInfo = CardDrawsConfig.INSTANCE.getCardDrawStaticInfo(cardDrawId);
                        cardDrawItem = cardDrawStaticInfo.draw();
                    } else if (winNum % 3 == 0) {
                        // 每赢满3场开小号卡包
                        cardDrawId = MapConfig.INSTANCE.hegemonySmallCardDrawId;
                        CardDrawStaticInfo cardDrawStaticInfo = CardDrawsConfig.INSTANCE.getCardDrawStaticInfo(cardDrawId);
                        cardDrawItem = cardDrawStaticInfo.draw();
                    }
                } else {
                    target.status = Consts.HEGEMONY_TARGET_STATUS_LOST;

                    rewardSilver = (int) (targetPower * humanRankConfig.hegemonySilverCoef / 2);
                }

                // 发送战斗结果给客户端
                sendMessage(ClientToMapBuilder.buildHegemonyBattleResult(battleResult, stimulate, rewardSilver, rewardRankExp, cardDrawItem, cardDrawId == MapConfig.INSTANCE.hegemonyBigCardDrawId));

                if (oldStatus != target.status) {
                    // 发送目标状态给客户端
                    sendMessage(ClientToMapBuilder.buildHegemonyTargetStatusChange(targetSlot, target.status));
                }

                // 发奖励
                if (rewardSilver > 0) {
                    increaseSilver(rewardSilver, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY, targetSlot, true);
                }

                if (rewardRankExp > 0) {
                    increaseRankExperience(rewardRankExp, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY, targetSlot, true);
                }

                // 发宝箱奖励
                if (cardDrawItem != null) {
                    cards.addCard(cardDrawItem.cardId, cardDrawItem.level, 0, true);
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] get hegemony battle result of target slot[" + targetSlot + "] but no battle is running."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] get hegemony battle result of target slot[" + targetSlot + "] when hegemony not open."));
        }
    }

    public void refreshHegemony(int count) {
        if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
            if (!hegemonyTargets.isFighting) {
                // 若全胜则免费刷新
                if (hegemonyTargets.isAllWin()) {
                    hegemonyTargets.refresh();
                } else {
                    int needGold = 0;
                    int currentDay = (int) ((GameServer.INSTANCE.getCurrentTime()+Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
                    if (currentDay > lastRefreshHegemonyDay) {
                        refreshHegemonyCount = 0;
                        lastRefreshHegemonyDay = currentDay;
                    }

                    if (refreshHegemonyCount == count) {
                        int pos = 0;
                        VipNumGold[] vipNumGolds = MapConfig.INSTANCE.refreshHegemonyGolds;

                        // 根据已使用次数查询对应的VipNumGold对象
                        for (pos = 0; pos < vipNumGolds.length; pos++) {
                            if (vipNumGolds[pos].num >= refreshHegemonyCount+1) {
                                break;
                            }
                        }

                        if (pos < vipNumGolds.length) {
                            needGold = (vipNumGolds[pos].vip > vip.level)?vipNumGolds[pos].gold:0;

                            if (getGold() >= needGold) {
                                decreaseGold(needGold, Consts.SOUL_CHANGE_LOG_TYPE_REFRESH_HEGEMONY, Consts.SOUL_CHANGE_LOG_SUBTYPE_NONE, true, true);
                                hegemonyTargets.refresh();    // 刷新争霸列表
                                refreshHegemonyCount ++;
                                sendMessage(ClientToMapBuilder.buildRefreshHegemony(refreshHegemonyCount,lastRefreshHegemonyDay));

                                // 记录行为日志
                                if (MapConfig.INSTANCE.useCYLog == true) {
                                    List<String> cyLogList = new ArrayList<String>();
                                    cyLogList.add("behaviorMC");
                                    cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                                    cyLogList.add("KDTY");
                                    cyLogList.add(String.valueOf(id));
                                    cyLogList.add(name);
                                    cyLogList.add("");
                                    cyLogList.add("RefreshHegemonyDBBehavior");
                                    cyLogList.add(refreshHegemonyCount + "");
                                    cyLogList.add("");
                                    cyLogList.add("");
                                    cyLogList.add("");
                                    cyLogList.add("");
                                    cyLogList.add("");
                                    GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
                                }
                                GameLogger.getlogger().log(GameLogMessageBuilder.buildRefreshHegemonyDBBehaviorGameLogMessage(id, refreshHegemonyCount));
                            } else {
                                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                        "Player[" + id + "] can't refresh hegemony because not enough gold"));
                            }
                        } else {
                            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                    "Player[" + id + "] can't refresh hegemony because times limit"));
                        }
                    } else {
                        GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                                FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                                "Player[" + id + "] can't refresh hegemony because count not match."));
                    }
                }
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't refresh hegemony because is fighting."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't refresh hegemony because level limit."));
        }
    }

    public void getHegemonyPay() {
        if (lv >= MapConfig.INSTANCE.openHegemonyLevel) {
            int currentDay = (int) ((GameServer.INSTANCE.getCurrentTime()+Consts.JET_LAG) / (Consts.MILSECOND_ONE_DAY));
            if (currentDay > lastHegemonyPayDay) {
                lastHegemonyPayDay = currentDay;
                HumanRankConfig humanRankConfig = HumanRanksConfig.INSTANCE.rankConfigs[rankLv-1];

                // 发军饷
                if (humanRankConfig.paySilver > 0) {
                    increaseSilver(humanRankConfig.paySilver, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY_PAY, rankLv, true);
                }

                if (humanRankConfig.payGold > 0) {
                    increaseSilver(humanRankConfig.payGold, Consts.SOUL_CHANGE_LOG_TYPE_HEGEMONY_PAY, rankLv, true);
                }

                // 通知客户端
                sendMessage(ClientToMapBuilder.buildHegemonyGetPay(lastHegemonyPayDay, humanRankConfig.paySilver, humanRankConfig.payGold));
            } else {
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                        FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                        "Player[" + id + "] can't get hegemony pay because already pay."));
            }
        } else {
            GameLogger.getlogger().log(GameLogMessageBuilder.buildFileDebugGameLogMessage(
                    FileDebugGameLogMessage.DebugLogType.DEBUGLOGTYPE_ERROR,
                    "Player[" + id + "] can't get hegemony pay because level limit."));
        }
    }

    public void getBaseTargets() {
        if (baseTargets == null) {
            baseTargets = new BaseTargets(this);
        }

        baseTargets.getInfo();
    }

    public BaseAttackBattle createBaseAttackBattle(int targetIndex, int targetId, Human targetHuman) {
        BaseAttackBattle baseAttackBattle = new BaseAttackBattle(id, targetIndex, targetId);

        // 取出队长卡片数据
        Card leaderCard = sandbox.slots[sandbox.leader];
        TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

        float hpChange = (barrack != null)?1.0f+barrack.hpIncrease:1.0f;
        float atkChange = (ordnance != null)?1.0f+ordnance.atkIncrease:1.0f;
        int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
        int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
        // 加入玩家战士
        for (int i=0; i<Consts.MAX_SANDBOX_SLOT_NUM; i++) {
            Card card = sandbox.slots[i];
            if (card != null) {
                Fighter fighter = new Fighter(i, baseAttackBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, null, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                baseAttackBattle.addFighter(fighter);
            }
        }

        // 取出对手队长卡片数据
        SandBox targetSandBox = targetHuman.sandbox;
        Card targetLeaderCard = targetSandBox.slots[targetSandBox.leader];
        TalentStaticInfo targetLeaderTalentStaticInfo = (targetLeaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[targetLeaderCard.staticInfo.leaderTalentId]:null;

        float targetHpChange = (targetHuman.barrack != null)?1.0f+targetHuman.barrack.hpIncrease:1.0f;
        float targetAtkChange = (targetHuman.ordnance != null)?1.0f+targetHuman.ordnance.atkIncrease:1.0f;
        int targetCriAndTenChange = (targetHuman.council != null)?targetHuman.council.criAndTenIncrease:0;
        int targetHitAndDodChange = (targetHuman.training != null)?targetHuman.training.hitAndDodIncrease:0;
        // 加入对手战士，并计算对手总战力
        for (int i=0; i<Consts.MAX_SANDBOX_SLOT_NUM; i++) {
            Card card = targetSandBox.slots[i];
            if (card != null) {
                Fighter fighter = new Fighter(Consts.MAX_SANDBOX_SLOT_NUM + i, baseAttackBattle, card.staticInfo, card.level, Long.MAX_VALUE, targetLeaderTalentStaticInfo, null, false, 0, targetHpChange, targetAtkChange, targetCriAndTenChange, targetHitAndDodChange);
                baseAttackBattle.addFighter(fighter);
            }
        }

        return baseAttackBattle;
    }

    public BaseResistanceBattle createBaseResistanceBattle(int king, Human targetHuman, boolean stimulate) {
        BaseResistanceBattle baseResistanceBattle = new BaseResistanceBattle(id, king, stimulate);

        // 取出队长卡片数据
        Card leaderCard = sandbox.slots[sandbox.leader];
        TalentStaticInfo leaderTalentStaticInfo = (leaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[leaderCard.staticInfo.leaderTalentId]:null;

        float hpChange = (stimulate?0.5f:0) + ((barrack != null)?1.0f+barrack.hpIncrease:1.0f);
        float atkChange = (stimulate?0.5f:0) + ((ordnance != null)?1.0f+ordnance.atkIncrease:1.0f);
        int criAndTenChange = (council != null)?council.criAndTenIncrease:0;
        int hitAndDodChange = (training != null)?training.hitAndDodIncrease:0;
        // 加入玩家战士
        for (int i=0; i<Consts.MAX_SANDBOX_SLOT_NUM; i++) {
            Card card = sandbox.slots[i];
            if (card != null) {
                Fighter fighter = new Fighter(i, baseResistanceBattle, card.staticInfo, card.level, Long.MAX_VALUE, leaderTalentStaticInfo, null, false, 0, hpChange, atkChange, criAndTenChange, hitAndDodChange);
                baseResistanceBattle.addFighter(fighter);
            }
        }

        // 取出对手队长卡片数据
        SandBox targetSandBox = targetHuman.sandbox;
        Card targetLeaderCard = targetSandBox.slots[targetSandBox.leader];
        TalentStaticInfo targetLeaderTalentStaticInfo = (targetLeaderCard.staticInfo.leaderTalentId != -1)?TalentsConfig.INSTANCE.talentStaticInfos[targetLeaderCard.staticInfo.leaderTalentId]:null;

        float targetHpChange = (targetHuman.barrack != null)?1.0f+targetHuman.barrack.hpIncrease:1.0f;
        float targetAtkChange = (targetHuman.ordnance != null)?1.0f+targetHuman.ordnance.atkIncrease:1.0f;
        int targetCriAndTenChange = (targetHuman.council != null)?targetHuman.council.criAndTenIncrease:0;
        int targetHitAndDodChange = (targetHuman.training != null)?targetHuman.training.hitAndDodIncrease:0;
        // 加入对手战士，并计算对手总战力
        for (int i=0; i<Consts.MAX_SANDBOX_SLOT_NUM; i++) {
            Card card = targetSandBox.slots[i];
            if (card != null) {
                Fighter fighter = new Fighter(Consts.MAX_SANDBOX_SLOT_NUM + i, baseResistanceBattle, card.staticInfo, card.level, Long.MAX_VALUE, targetLeaderTalentStaticInfo, null, false, 0, targetHpChange, targetAtkChange, targetCriAndTenChange, targetHitAndDodChange);
                baseResistanceBattle.addFighter(fighter);
            }
        }

        return baseResistanceBattle;
    }

    public void flushData() {
        // 只有当玩家在线时才需要向数据库同步保存数据
        if (inGame) {
            // 将玩家信息入库
            DBMessageQueue.queue().offer(MapDBMessageBuilder.buildSaveCharInfoDBMessage(id, buildCharDetailInfo()));
        }
    }

    public CharDetailInfo buildCharDetailInfo() {
        CharDetailInfo charDetailInfo = new CharDetailInfo();

        charDetailInfo.mid = id;
        charDetailInfo.name = name;
        charDetailInfo.gold1 = gold1;
        charDetailInfo.gold2 = gold2;
        charDetailInfo.silver = silver;
        charDetailInfo.energy = energy;
        charDetailInfo.token = token;
        charDetailInfo.level = lv;
        charDetailInfo.experience = exp;
        charDetailInfo.rankLevel = rankLv;
        charDetailInfo.rankExperience = rankExp;
        Card leaderCard = sandbox.slots[sandbox.leader];
        charDetailInfo.leaderCardId = leaderCard.staticInfo.id;
        charDetailInfo.leaderCardLevel = leaderCard.level;
        charDetailInfo.vipLevel = vip.level;
        charDetailInfo.vipExperience = vip.exp;
        charDetailInfo.maxPower = maxPower;

        charDetailInfo.detail = humanProtocolBuilder.buildPlayerDetail();
        charDetailInfo.mailInfo = mails.buildDBMailsProto();

        charDetailInfo.totalOnlineTime = totalOnlineTime;
        charDetailInfo.leaveTime = leaveTime;

        return charDetailInfo;
    }

    public void lookOtherPlayerDetailInfo(Human target) {
        if (target != null) {
            // TODO: 发送消息
//            sendMessage(ClientToMapBuilder.buildOtherPlayerDetail(otherPlayer.humanProtocolBuilder.buildOtherPlayerInfoProto()));

            if (MapConfig.INSTANCE.useCYLog == true) {
                List<String> cyLogList = new ArrayList<String>();
                cyLogList.add("behaviorMC");
                cyLogList.add(String.valueOf(MapConfig.INSTANCE.gameId));
                cyLogList.add("KDTY");
                cyLogList.add(String.valueOf(id));
                cyLogList.add(name);
                cyLogList.add("");
                cyLogList.add("GetPlayerInfoDBBehavior");
                cyLogList.add(target.id + "");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                cyLogList.add("");
                GameLogger.getlogger().log(GameLogMessageBuilder.buildFileCYGameLogMessage(cyLogList, GameLogType.GAMELOGTYPE_CY_BEHAVIOR));
            }
            GameLogger.getlogger().log(GameLogMessageBuilder.buildGetPlayerInfoDBBehaviorGameLogMessage(id, target.id));
        }
    }

    public void addCouponReward(String code, CertainRewardInfo reward) {
        if(reward != null){
            digestCertainReward(reward, Consts.SOUL_CHANGE_LOG_TYPE_GETREWARD_COUPON, 0);

            sendMessage(ClientToMapBuilder.buildGetCoupon(reward));
            DBMessageQueue.queue().offer(MapDBMessageBuilder.buildGetCouponDBMessage(id, mapPlayer.passport, code));
        } else {
            // 发失败给客户端
            sendMessage(ClientToMapBuilder.buildGetCouponError());
        }
    }

    public void sendMessage(ProtobufMessage message) {
        if ((mapPlayer != null) && (mapPlayer.channelContext != null)) {
            mapPlayer.channelContext.write(message);
        }
    }

    public void broadcastToFriends(ProtobufMessage message) {
        if ((relation != null) && !relation.friends.isEmpty()) {
            GameServer.INSTANCE.broadcast(relation.friends, message, true);
        }
    }

    public void increaseEnergyGM() {
        int maxEnergy = HumanLevelsConfig.INSTANCE.levelConfigs[lv - 1].maxEnergy;
        energy = maxEnergy;
        sendMessage(ClientToMapBuilder.buildEnergyChange(energy));
    }

    public void ignoreGuideStep() {
        guideStep = 0;
    }
}
